<template>
  <a-modal
    :visible.sync="visible"
    :title="title"
    :width="String(width).endsWith('px') ? width : width + 'px'"
    :footer="null"
    @cancel="close"
  >
    <ul :class="center ? 'transform-center' : ''" class="c-dialog-flex">
      <li
        v-for="i in columnInfo"
        :key="i.key"
        :style="{ width: 100 / (i.width || 1) + '%' }"
      >
        <div v-if="i.bind && i.bind.value.includes(formInfo[i.bind.key])">
          <label
            :class="[i.need ? 'must' : '']"
            name="i.key"
            :style="{ flex: '0 0 ' + labelWidth }"
            >{{ i.label + ':' }}</label
          >
          <div :class="[i.innerClass]" :name="i.key" :data-comdialog="i.key">
            <span
              v-if="i.type === 'input'"
              :class="!showWarn(i.need, i.warning) ? 'cps-error' : ''"
            >
              <a-input
                v-model.trim="formInfo[i.key]"
                :max-length="i.maxLength || 100"
                @blur="e => blurValue(e, i)"
                @change="
                  e => {
                    change(e, i)
                  }
                "
            /></span>
            <span
              v-if="i.type === 'radio'"
              :class="!showWarn(i.need, i.warning) ? 'cps-error' : ''"
            >
              <a-radio-group
                v-model.trim="formInfo[i.key]"
                @change="
                  e => {
                    change(e, i)
                  }
                "
              >
                <a-radio
                  v-for="item in i.radioOption"
                  :key="item.value"
                  :value="item.value"
                >
                  {{ item.label }}
                </a-radio>
              </a-radio-group>
            </span>
            <slot
              v-if="i.key === i.slot"
              :id="id"
              :close="close"
              :width="labelWidth"
              :scope="i"
              :name="i.slot"
            />
            <!-- 插槽详细用法 -->
            <!-- 和key为name1的数据联动，只支持一对一联动 不支持一对多  name1等于1才展示 -->
          </div>
        </div>
        <div v-if="!i.bind">
          <label
            :class="[i.need ? 'must' : '']"
            name="i.key"
            :style="{ flex: '0 0 ' + labelWidth }"
            >{{ i.label + ':' }}</label
          >
          <div :class="[i.innerClass]" :name="i.key" :data-comdialog="i.key">
            <span
              v-if="i.type === 'radio'"
              :class="!showWarn(i.need, i.warning) ? 'cps-error' : ''"
            >
              <a-radio-group
                v-model.trim="formInfo[i.key]"
                @change="
                  e => {
                    change(e, i)
                  }
                "
              >
                <a-radio
                  v-for="item in i.radioOption"
                  :key="item.value"
                  :value="item.value"
                >
                  {{ item.label }}
                </a-radio>
              </a-radio-group>
            </span>
            <span
              v-if="i.type === 'input'"
              :class="showWarn(i.need, i.warning) ? 'cps-error' : ''"
            >
              <a-input
                v-model.trim="formInfo[i.key]"
                :type="i.inputType || 'text'"
                :max-length="i.maxLength || 100"
                @blur="e => blurValue(e, i)"
                @change="
                  e => {
                    change(e, i)
                  }
                "
            /></span>
            <span
              v-if="i.type === 'select'"
              :class="showWarn(i.need, i.warning) ? 'cps-error' : ''"
            >
              <a-select
                v-model.trim="formInfo[i.key]"
                style="width: 170px"
                @blur="e => blurValue(e, i)"
                @change="
                  e => {
                    change(e, i)
                  }
                "
              >
                <a-select-option
                  v-for="sel in i.options"
                  :key="sel.label"
                  :value="sel.value"
                >
                  {{ sel.label }}</a-select-option
                >
              </a-select>
            </span>
            <slot
              v-if="i.key === i.slot"
              :id="id"
              :close="close"
              :width="labelWidth"
              :name="i.slot"
            />
            <!-- 插槽详细用法 -->
          </div>
        </div>
        <p
          v-if="showWarn(i.need, i.warning)"
          :name="formInfo[i.key]"
          class="reset-p"
          :style="{ paddingLeft: labelWidth }"
        >
          <span>{{ i.warningText || `${i.label}不能为空` }}</span>
        </p>
      </li>
      <slot name="footer" />
    </ul>
    <slot />
    <div class="text-center">
      <a-button style="margin-right: 10px" @click="close"> 取消 </a-button>
      <a-button type="primary" @click="submit"> 确定 </a-button>
    </div>
  </a-modal>
</template>
<script>
import { debounce } from 'lodash'
export default {
  // directives 加入指令，绑定必填数据的校验 filter
  props: {
    center: {
      type: Boolean,
      default: false
    },
    title: {
      type: String,
      default: '操作弹框'
    },
    width: {
      type: [String, Number],
      default: 800
    },
    columns: {
      type: Array,
      default: () => []
    },
    value: {
      type: Boolean,
      default: false
    },
    form: {
      type: Object,
      default: () => {
        return {}
      }
    }
  },
  data() {
    return {
      labelWidth: '100px' // label 宽度设置 自使用
    }
  },
  computed: {
    formInfo() {
      return this.form
    },
    visible() {
      return this.value
    },
    columnInfo() {
      return this.setColumn()
    },
    showWarn() {
      return (need, cur) => {
        return need && cur
      }
    }
  },
  created() {
    this.labelWidth =
      Math.max(
        ...this.columns.map(_ => {
          return _.label.length
        })
      ) +
      1 +
      'em'
    this.change = debounce(this.change, 300)
  },
  methods: {
    blurValue(e, scope) {
      //  失去光标校验   or  正则校验
      if (scope.pattern && !scope.pattern.test(e.target.value)) {
        // false
        Object.assign(scope, { warning: true })
        this.$emit('dispatchQuery', this.formInfo)
        this.$parent &&
          this.$parent.fetchRelation &&
          this.$parent.fetchRelation(this.formInfo)
        this.$forceUpdate()
        return
      }
      if (scope.need) {
        if (e.target.value === '' && 'warning' in scope) {
          // 为空校验
          Object.assign(scope, { warning: true })
        } else {
          Object.assign(scope, { warning: false })
        }
        if (scope.fn) {
          scope.fn(e, scope)
        }
      }
      this.$emit('dispatchQuery', this.formInfo)
      this.$parent &&
        this.$parent.fetchRelation &&
        this.$parent.fetchRelation(this.formInfo)
      this.$forceUpdate()
    },
    setColumn() {
      //
      this.columns.forEach(_ => {
        _.need && (_.warning = false)
        _.value && (this.formInfo[_.key] = _.defaultValue)
      })
      return this.columns
    },
    change(e, scope) {
      if (scope.checked) {
        this.formInfo[scope.checked.key] = ''
        Object.assign(this.formInfo, { [scope.checked.key]: '' })
      }
      this.blurValue(e, scope)
    },
    close() {
      this.setColumn()
      Object.keys(this.formInfo).forEach(_ => {
        Object.assign(this.formInfo, { [_]: '' })
      })
      this.$emit('input', false)
    },
    submit() {
      const pass = []
      this.columns.forEach(_ => {
        if (!this.formInfo[_.key] && _.need) {
          Object.assign(_, { warning: true })
        }
        _.warning && pass.push(_.warning)
      })
      if (pass.length) {
        // 报错
        this.$message.error('有必填项未填写！')
      } else {
        // 提交数据
        this.$emit('sumit', this.formInfo)
      }
      this.$forceUpdate()
    }
  }
}
/**
 * 常用正则   /^\d{n}$/
 * 带1-2位小数的正数或负数：/^(\-)?\d+(\.\d{1,2})?$/  ^[1-9]\d*$
 * 英文和数字：^[A-Za-z0-9]+$
 * ^\d{15}|\d{18}｜\d{17}X$
 * https://www.cnblogs.com/dreamingbaobei/p/9717234.html
 */
</script>
<style lang="less" scoped>
.transform-center {
  transform: translate(25%);
}
.c-dialog-flex {
  display: flex;
  flex-wrap: wrap;
  list-style-type: none;
  padding: 20px 0 10px 0;
  margin: 0;
  li {
    margin: 0 0 10px 0;
    transform: all 1s;

    padding-left: 6px;
    &:empty {
      display: none;
    }
    & > div {
      display: flex;
      align-items: center;
    }
  }
}
.c-inline-block {
  display: inline-block;
}
.must::before {
  content: '*';
  color: red;
}
.pos-absolute {
  position: absolute;
}
.reset-p {
  margin: 0;
  padding: 0;
  color: red;
}
.text-center {
  text-align: center;
}
.cps-error {
  & .ant-input {
    border: 1px solid red;
  }
  & .ant-select {
    border: 1px solid red;
  }
}
</style>
